package com.mrogrape.gui.plaf;

import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.swing.ButtonGroup;
import javax.swing.JMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.UIManager.LookAndFeelInfo;

public class LookAndFeelLibrary {

	private static final String bundleName = "com.mrogrape.gui.plaf.resources.LookAndFeelLibrary";

	private static final ResourceBundle resources = ResourceBundle.getBundle(LookAndFeelLibrary.bundleName);

	public static final String METAL = "javax.swing.plaf.metal.MetalLookAndFeel";

	public static final String MOTIF = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";

	public static final String NIMBUS = "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";

	public static final String WINDOWS = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";

	public static final String WINDOWS_CLASSIC = "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel";


	/**
	 * 向系统观感库中安装此观感库中提供的观感。
	 * 
	 */
	public static final void installLookAndFeel(){
		LookAndFeelLibrary.findLookAndFeels();

		for(CustomLookAndFeel laf : LookAndFeelLibrary.extendedLookAndFeelList){
			UIManager.installLookAndFeel(laf.getName(), laf.getClassName());
		}
	}

	/**
	 * 跟据一个观感的类名创建一个观感对象。
	 * 
	 * @param className 观感类名。
	 * @return 创建的观感对象。
	 * @throws ClassNotFoundException 如果观感未找到。
	 * @throws UnsupportedLookAndFeelException 如果观感不被支持。
	 */
	public static LookAndFeel createLookAndFeel(String className)
	throws ClassNotFoundException, UnsupportedLookAndFeelException {
		Object obj = null;

		try {
			obj = Class.forName(className).newInstance();
		} catch (InstantiationException e) {
			return null;
		} catch (IllegalAccessException e) {
			return null;
		}

		if(!(obj instanceof LookAndFeel)){
			throw new UnsupportedLookAndFeelException(className);
		}

		return (LookAndFeel) obj;
	}

	// TODO IMPL
	public static JMenu createLookAndFeelMenu(String label,Component... c){
		if(label == null || c == null){
			throw new NullPointerException();
		}

		LookAndFeelInfo lafs[] = UIManager.getInstalledLookAndFeels();
		int numbers = lafs.length;

		HashMap<String,String> lafMap = new HashMap<String,String>();

		JRadioButtonMenuItem[] menuItems = new JRadioButtonMenuItem[numbers];

		for(int i = 0; i<numbers;i++){
			LookAndFeelInfo laf = lafs[i];
			String name = laf.getName();
			String className = laf.getClassName();
			lafMap.put(name, className);
			menuItems[i] = new JRadioButtonMenuItem(name);

		}

		JMenu menu = new JMenu(label);
		ButtonGroup group = new ButtonGroup();
		String currentLaf = UIManager.getLookAndFeel().getName();
		for(JRadioButtonMenuItem item : menuItems){
			if(item.getText().equals(currentLaf)){
				item.setSelected(true);
			}
			menu.add(item);
			group.add(item);
			item.addActionListener(new LookAndFeelChangedListener(lafMap,c));
		}

		return menu;
	}

	private static class LookAndFeelChangedListener implements ActionListener{

		public LookAndFeelChangedListener(Map<String,String> lafMap,Component... c){
			this.components = c;
			this.lafMap = lafMap;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			Object source = e.getSource();
			String currentLaf = UIManager.getLookAndFeel().getName();

			if(source instanceof JRadioButtonMenuItem){
				JRadioButtonMenuItem item = (JRadioButtonMenuItem)source;
				final String name = item.getText();
				if(item.getText().equals(currentLaf)){
					return;
				}

				EventQueue.invokeLater(new Runnable(){

					@Override
					public void run() {
						String className = LookAndFeelChangedListener.this.lafMap.get(name);
						try {
							UIManager.setLookAndFeel(className);
						} catch (Exception e) {
							System.out.println("UnsupportedLookAndFeel");
							return;
						} 
						Window windows[] = Window.getWindows();
						for (Window window : windows) {
							SwingUtilities.updateComponentTreeUI(window);
						}
						for(Component c : LookAndFeelChangedListener.this.components){
							SwingUtilities.updateComponentTreeUI(c);
							c.validate();
						}

					}

				});

			}
		}

		private Component[] components = null;
		private Map<String,String> lafMap = null;

	}

	private static String getProperty(String key){
		try{
			return LookAndFeelLibrary.resources.getString(key);
		}catch(Exception e){
			return null;
		}
	}


	private static void findLookAndFeels() {

		String lafsStr = LookAndFeelLibrary
		.getProperty(LookAndFeelLibrary.KEY_LAFS);
		String[] lafs = lafsStr.split(LookAndFeelLibrary.SEPARATOR);
		for (String lafname : lafs) {
			String name = LookAndFeelLibrary.getProperty(lafname + "."
					+ LookAndFeelLibrary.KEY_NAME);
			String className = LookAndFeelLibrary.getProperty(lafname + "."
					+ LookAndFeelLibrary.KEY_CLASSNAME);
			String author = LookAndFeelLibrary.getProperty(lafname + "."
					+ LookAndFeelLibrary.KEY_AUTHOR);
			String copyright = LookAndFeelLibrary.getProperty(lafname + "."
					+ LookAndFeelLibrary.KEY_COPYRIGHT);
			String license = LookAndFeelLibrary.getProperty(lafname + "."
					+ LookAndFeelLibrary.KEY_LICENSE);
			// Find theme
			String themeStr = LookAndFeelLibrary.getProperty(lafname + "."
					+ LookAndFeelLibrary.KEY_THEME);
			String[] themeArray = themeStr.split(LookAndFeelLibrary.SEPARATOR);
			LookAndFeelTheme[] themes = new LookAndFeelTheme[themeArray.length];
			for (int i = 0; i < themeArray.length; i++) {
				String themeName = themeArray[i];
				String themeClassName = LookAndFeelLibrary.getProperty(lafname
						+ "." + LookAndFeelLibrary.KEY_THEME + "." + themeName);
				themes[i] = new LookAndFeelTheme(name, themeClassName);
			}
			CustomLookAndFeel aLaf = new CustomLookAndFeel(name, className,
					author, copyright, license, themes);
			LookAndFeelLibrary.extendedLookAndFeelList.add(aLaf);
			System.out.println("New Look And Feel installed!");
			System.out.println("****************************");
			System.out.println(aLaf);
		}
	}

	private static final String SEPARATOR = ";";
	private static final String KEY_LAFS = "installed_laf";
	private static final String KEY_NAME = "name";
	private static final String KEY_CLASSNAME = "class_name";
	private static final String KEY_AUTHOR = "author";
	private static final String KEY_COPYRIGHT = "copyright";
	private static final String KEY_LICENSE = "license";
	private static final String KEY_THEME = "theme";

	private static List<CustomLookAndFeel> extendedLookAndFeelList = new ArrayList<CustomLookAndFeel>();

	protected static class CustomLookAndFeel{
		String name;
		String className;
		String author;
		String copyright;
		String license;
		LookAndFeelTheme[] themes;

		public CustomLookAndFeel(String name, String className, String author,
				String copyright, String license, LookAndFeelTheme[] themes) {

			this.name = name;
			this.className = className;
			this.author = author;
			this.copyright = copyright;
			this.license = license;
			this.themes = themes;
		}

		public String getName() {

			return this.name;
		}
		public void setName(String name) {

			this.name = name;
		}
		public String getClassName() {

			return this.className;
		}
		public void setClassName(String className) {

			this.className = className;
		}
		public String getAuthor() {

			return this.author;
		}
		public void setAuthor(String author) {

			this.author = author;
		}
		public String getCopyright() {

			return this.copyright;
		}
		public void setCopyright(String copyright) {

			this.copyright = copyright;
		}
		public String getLicense() {

			return this.license;
		}
		public void setLicense(String license) {

			this.license = license;
		}
		public LookAndFeelTheme[] getThemes() {

			return this.themes;
		}
		public void setThemes(LookAndFeelTheme[] themes) {

			this.themes = themes;
		}

		@Override
		public String toString() {

			StringBuilder sb = new StringBuilder();

			sb.append("Name : " + this.name + "\n");
			sb.append("Class Name : " + this.className + "\n");
			sb.append("Author : " + this.author + "\n");
			sb.append("Copyright : " + this.copyright + "\n");
			sb.append("License : " + this.license + "\n");

			return sb.toString();
		}



	}

	protected static class LookAndFeelTheme{
		String name;
		String className;
		public String getName() {

			return this.name;
		}
		public void setName(String name) {

			this.name = name;
		}
		public String getClassName() {

			return this.className;
		}
		public void setClassName(String className) {

			this.className = className;
		}
		public LookAndFeelTheme(String name, String className) {

			super();
			this.name = name;
			this.className = className;
		}


	}



}
